/**
 * @file text_data.c
 *
 * @date Oct 11, 2011
 * @author seth
 *
 * @brief This file is part of EBEX State Estimator, created for the EBEX project
 *
 * This software is copyright (C) 2011 Columbia University
 *
 * EBEX State Estimator is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * EBEX State Estimator is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with EBEX State Estimator; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <inttypes.h>

#include <log_util.h>
#include <memory_util.h>
#include <data_file.h>
#include <text_data.h>

void text_data_close(data_file_t *m_file)
{
	elog(log_level_extreme, "Closing file %s", m_file->filename?m_file->filename:"(Empty Filename)");

	if (m_file->fp) fclose(m_file->fp);
	e_free_quiet(m_file->filename);


	m_file->fp = NULL;
	m_file->filename = NULL;
}

bool text_data_open(data_file_t *m_file, const char *m_filename, size_t m_offset)
{
	char *input_databuffer = NULL;
	size_t databuffer_size = 0;

	if (!m_file)
	{
		elog(log_level_fatal, "Passed NULL pointer");
		return false;
	}
	if (!m_filename)
	{
		elog(log_level_fatal, "Asked to open NULL filename");
		return false;
	}


	if (!(m_file->fp = fopen(m_filename, m_file->is_sink ? "w" : "r")))
	{
		elog(log_level_fatal, "Could not open %s for %s", m_filename, m_file->is_sink ? "writing" : "reading");
		return false;
	}

	m_file->filename = e_strdup(m_filename);

	m_file->type = DATA_FILE_ASCII;
	m_file->stride = 1;

	m_file->conf.ascii.column = 0;
	m_file->conf.ascii.delimiters = NULL;
	m_file->num_elements = 0;

	while (getline(&input_databuffer, &databuffer_size, m_file->fp) != -1)
	{
		if (++m_file->num_elements == m_offset) m_file->offset = ftello(m_file->fp);
	}

	fseeko(m_file->fp, m_file->offset, SEEK_SET);
	elog(log_level_verbose, "File %s opened with %zu elements.  Setting start to element %lu", m_file->filename, m_file->num_elements, (unsigned long)m_offset);

	e_free_quiet(input_databuffer);

	return true;
}

bool text_data_reset(data_file_t *m_file)
{

	if (!m_file)
	{
		elog(log_level_fatal, "Passed NULL pointer");
		return false;
	}

	fseeko(m_file->fp, m_file->offset, SEEK_SET);
	elog(log_level_verbose, "File %s reset to starting byte %zu", m_file->filename, m_file->offset);

	return true;
}
/**
 * Fills the data databuffer with text data (e.g. CSV).  The databuffer will be filled from the current position
 * in the open file and placed in the databuffer at position
 * @param m_source Pointer to the data source
 * @param m_buffer Offset pointer to the receiving data buffer
 * @param m_numelements Number of doubles to insert into the buffer
 * @return Number of elements actually inserted
 */
size_t text_data_fillbuffer(data_file_t *m_source, double *m_buffer, const size_t m_numelements)
{
	size_t element_to_read;
	size_t elements_to_skip = 0;
	size_t elements_read = 0;

	char *input_databuffer = NULL;
	size_t databuffer_size = 0;
	char *temp_ptr = NULL;
	char *token = NULL;
	size_t token_num = 0;

	element_to_read = m_numelements;
	elements_to_skip = m_source->stride;

	do
	{
		if ( (getline(&input_databuffer, &databuffer_size, m_source->fp) == -1))
		{
			break;
		}
		if (! --elements_to_skip)
		{

			temp_ptr = input_databuffer;
			token_num = 0;
			while ((token = strsep(&temp_ptr, m_source->conf.ascii.delimiters)))
			{
				if(token_num++ == m_source->conf.ascii.column)
				{
					*m_buffer++ = strtod(token, NULL);
					break;
				}
			}
			if (!token)
			{
				elog(log_level_normal, "Could not locate column %zu in data buffer", m_source->conf.ascii.column);
				break;
			}

			elements_read++;
			elements_to_skip = MAX((size_t)1,m_source->stride);
		}

	} while (--element_to_read && !feof(m_source->fp));


	e_free_quiet(input_databuffer);
	return elements_read;
}

size_t text_data_writebuffer(data_file_t *m_source, double *m_buffer, const size_t m_numelements)
{
	size_t num_written = 0;
	double *buffer = m_buffer;
	while (num_written < m_numelements)
	{
		if (fprintf(m_source->fp, "%01.16f", *buffer++) < 0) break;
		if (m_source->stride == 1 || m_source->conf.ascii.column == m_source->stride)
		{
			fprintf(m_source->fp, "\n");
		}
		else
		{
			fprintf(m_source->fp, ",");
		}
		num_written++;
	}
	return num_written;
}
bool text_data_set_parameters(data_file_t *m_source, const void *m_param)
{
	text_data_param_t *param = (text_data_param_t*)m_param;

	m_source->conf.ascii.column = param->column;
	m_source->stride = param->stride;
	m_source->conf.ascii.delimiters = e_strdup(param->delimiters);
	return true;
}
